#include <iostream>

using std::cout;
using std::endl;

template <typename T>
class RAII{
public:
    //1、在构造函数中初始化资源
    //2、在析构函数中释放资源
    //3、一般不允许复制和赋值
    //4、提供若干访问资源的方法
    
    RAII(T *pdata)
    : _pdata(pdata)
    {
        cout<<"RAII(T *)"<<endl;
    }

    ~RAII(){
        cout<<"~RAII()"<<endl;
        if(_pdata){
            delete _pdata;
            _pdata=nullptr;
        }
    }

    T *operator->(){
        return _pdata;
    }

    T &operator*(){
        return *_pdata;
    }

    T *get() const {    //降为裸指针
        return _pdata;
    }

    void reset(T *pdata){
        if(_pdata){
            delete _pdata;
            _pdata=nullptr;
        }
        _pdata=pdata;
    }

    RAII(const RAII &rhs)=delete;
    RAII &operator=(const RAII &rhs)=delete;

private:
    T *_pdata;
};

class Point{
public:
    Point(int ix, int iy): _ix(ix),_iy(iy)
    {
        cout<<"Point(int, int)"<<endl;
    }
    ~Point(){
        cout<<"~Point()"<<endl;
    }

    void print() const{
        cout<<_ix<<' '<<_iy<<endl;
    }

private:
    int _ix;
    int _iy;
};


void test(){
    //利用pt栈对象的生命周期，管理了堆空间的资源 
    RAII<Point> pt(new Point(1,2));
    //这里有个关键点：
    //new出来的Point空间没有delete，是因为RAII的指针指向同一空间，
    //而在执行RAII析构函数时已经释放了这个空间
    //所以先调用Point构造函数，再调用RAII构造函数，析构时顺序刚好相反
    //pt 是智能指针
    pt->print();
    pt.operator*().print();
    
    cout<<endl;
    pt.reset(new Point(3,4));   
    //在reset时，把原来的(1,2)空间给释放了，因为_pdata指向了那一块空间
    pt.operator->()->print();
}

int main()
{   
    test();
    return 0;
}

